<?php

namespace app\subscribe\contract;


use think\Event;
use think\facade\Db;
use app\common\repositories\room\RoomLogRepository;
use app\common\repositories\bill\BillBasicRepository;
use app\common\repositories\room\RoomBasicRepository;
use app\common\repositories\bill\BillCatalogRepository;
use app\common\repositories\contract\ContractLogRepository;
use app\common\repositories\contract\ContractBillRepository;
use app\common\repositories\contract\ContractBasicRepository;
use app\common\repositories\contract\ContractLesseeRepository;
use app\common\repositories\property\basic\PropertyLogRepository;

class ContractSubscribe
{


    /**
     * 监听租赁创建
     * @param $data
     */
    public function onContractCreate($data)
    {
        $userId = $data['userId'] ?? 0;
        $contractInfo = $data['contractInfo'];

        ## 添加物业日志
        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);
        $propertyLogData['contract_id'] = $contractInfo['id'];
        $propertyLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $propertyLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $propertyLogData['remark'] = '租赁编号: ' . $contractInfo['number'] . ' 创建';
        $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);

        ## 添加合同日志
        /** @var ContractLogRepository $contractLogRepository */
        $contractLogRepository = app()->make(ContractLogRepository::class);
        $contractLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $contractLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $contractLogData['remark'] = $contractInfo['number'] . ' 租赁创建';
        $contractLogRepository->addData($contractInfo['items_id'], $contractLogData, $userId);

        ## 添加房间日志
        if ((int)$contractInfo['room_id'] > 0) {
            /** @var RoomLogRepository $roomLogRepository */
            $roomLogRepository = app()->make(RoomLogRepository::class);
            $roomLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
            $roomLogData['property_id'] = $contractInfo['property_id'] ?? 0;
            $roomLogData['remark'] = $contractInfo['number'] . ' 租赁创建';
            $roomLogRepository->addData($contractInfo['items_id'], $roomLogData, $userId);
        }

    }


    /**
     * 审核确认
     * @param $data
     * @return void
     *
     * @author Amos
     * 2024-03-20 14:27
     */
    public function onAuditFinishContract($data)
    {
        $contractId = $data['contractId'] ?? 0;
        $userId = $data['userId'] ?? 0;
        $status = $data['status'] ?? 0;
        $remark = $data['remark'] ?? '';
        if ($status == 7) {
            $remark .= '失败';
        }
        /** @var ContractBasicRepository $contractBasicRepository */
        $contractBasicRepository = app()->make(ContractBasicRepository::class);
        $contractInfo = $contractBasicRepository->get($contractId);

        ## 添加合同日志
        /** @var ContractLogRepository $contractLogRepository */
        $contractLogRepository = app()->make(ContractLogRepository::class);
        $contractLogData['remark'] = ' 审核确认' . $remark;
        $contractLogData['contract_id'] = $contractId;
        $contractLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $contractLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $contractLogRepository->addData($contractInfo['items_id'], $contractLogData, $userId);

        ## 添加物业日志
        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);

        $propertyLogData['contract_id'] = $contractInfo['id'];
        $propertyLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $propertyLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $propertyLogData['remark'] = '租赁编号: ' . $contractInfo['number'] . ' 审核确认' . $remark;
        $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);

        ## 审核通过 生成第一份账单
        if ($status == 1) {
            $this->generateFirstBill($contractInfo, $userId);
        }
    }


    /**
     * 续租
     * @param $data
     * @return void
     *
     * @author Amos
     * 2024-03-20 14:37
     */
    public function onExtendContract($data)
    {
        $endDate = $data['endDate'];
        $userId = $data['userId'] ?? 0;
        $contractId = $data['contractId'] ?? 0;

        /** @var ContractBasicRepository $contractBasicRepository */
        $contractBasicRepository = app()->make(ContractBasicRepository::class);
        $contractInfo = $contractBasicRepository->get($contractId);


        ## 添加合同日志
        /** @var ContractLogRepository $contractLogRepository */
        $contractLogRepository = app()->make(ContractLogRepository::class);
        $contractLogData['remark'] = '续租至 ' . $endDate;
        $contractLogData['contract_id'] = $contractId;
        $contractLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $contractLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $contractLogRepository->addData($contractInfo['items_id'], $contractLogData, $userId);

        ## 添加物业日志
        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);
        $propertyLogData['contract_id'] = $contractInfo['id'];
        $propertyLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
        $propertyLogData['property_id'] = $contractInfo['property_id'];
        $propertyLogData['remark'] = '租赁: ' . $contractInfo['number'] . '续租至 ' . $endDate;
        $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);
    }


    /**
     *  监听租赁作废
     * @param $data
     * @return void
     *
     * @author Amos
     * 2024-06-13 22:19
     */
    public function onInvalidContract($data)
    {
        $userId = $data['userId'] ?? 0;
        $contractId = $data['contractId'] ?? 0;
        $invalidRemark = $data['invalidRemark'] ?? '';


        ## 租客信息改为退租
        /** @var ContractLesseeRepository $contractLesseeRepository */
        $contractLesseeRepository = app()->make(ContractLesseeRepository::class);
        $contractLesseeRepository->throwALeaseByContractId($contractId);

        ## 房间状态改为空置
        /** @var RoomBasicRepository $roomBasicRepository */
        $roomBasicRepository = app()->make(RoomBasicRepository::class);

        $roomList = $roomBasicRepository->getSearch([])
            ->where('contract_id', $contractId)
            ->where('status', 2)->select();

        foreach ($roomList as $v) {
            # 退租空置房间
            $roomBasicRepository->roomRelieve($v['id'], $contractId, $userId);
        }

        /** @var ContractBasicRepository $contractBasicRepository */
        $contractBasicRepository = app()->make(ContractBasicRepository::class);
        $contractInfo = $contractBasicRepository->get($contractId);

        ## 添加合同日志
        /** @var ContractLogRepository $contractLogRepository */
        $contractLogRepository = app()->make(ContractLogRepository::class);
        $contractLogData['remark'] = '作废 ' . $invalidRemark;
        $contractLogData['contract_id'] = $contractId;
        $contractLogData['room_id'] = $contractInfo['room_id'] ?? 0;
        $contractLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $contractLogRepository->addData($contractInfo['items_id'], $contractLogData, $userId);

        ## 添加物业日志
        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);
        $propertyLogData['contract_id'] = $contractInfo['id'];
        $propertyLogData['room_id'] = $contractInfo['room_id'] ?? 0;
        $propertyLogData['property_id'] = $contractInfo['property_id'];
        $propertyLogData['remark'] = '租赁: ' . $contractInfo['number'] . '作废 ' . $invalidRemark;
        $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);

    }


    /**
     * 监听租赁退租
     * @param $data
     */
    public function onRefundContract($data)
    {
        $contractId = $data['contractId'] ?? 0;
        $isSettlement = $data['is_settlement'];
        $userId = $data['userId'] ?? 0;
        $endRemark = $data['end_remark'] ?? '';


        ## 租客信息改为退租
        /** @var ContractLesseeRepository $contractLesseeRepository */
        $contractLesseeRepository = app()->make(ContractLesseeRepository::class);
        $contractLesseeRepository->throwALeaseByContractId($contractId);


        ## 房间状态改为空置
        /** @var RoomBasicRepository $roomBasicRepository */
        $roomBasicRepository = app()->make(RoomBasicRepository::class);

        $roomList = $roomBasicRepository->getSearch([])
            ->where('contract_id', $contractId)
            ->where('status', 2)->select();

        foreach ($roomList as $v) {
            # 退租空置房间
            $roomBasicRepository->roomRelieve($v['id'], $contractId, $userId);
        }

        ##  退租不结算账单全都作废
        if ($isSettlement != 1) {
            /** @var BillBasicRepository $billBasicRepository */
            $billBasicRepository = app()->make(BillBasicRepository::class);
            $billBasicRepository->getSearch([])
                ->where('contract_id', $contractId)
                ->where('status', 'in', [1, 2, 3])->select()->each(function ($billInfo) use ($userId, $billBasicRepository) {
                    $billBasicRepository->invalidBillByContractId($billInfo, $userId, '退租不结算账单');
                });
        }

        /** @var ContractBasicRepository $contractBasicRepository */
        $contractBasicRepository = app()->make(ContractBasicRepository::class);
        $contractInfo = $contractBasicRepository->get($contractId);

        ## 添加合同日志
        /** @var ContractLogRepository $contractLogRepository */
        $contractLogRepository = app()->make(ContractLogRepository::class);
        $contractLogData['remark'] = '退租 ' . $endRemark;
        $contractLogData['contract_id'] = $contractId;
        $contractLogData['room_id'] = $contractInfo['room_id'] ?? 0;
        $contractLogData['property_id'] = $contractInfo['property_id'] ?? 0;
        $contractLogRepository->addData($contractInfo['items_id'], $contractLogData, $userId);

        ## 添加物业日志
        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);
        $propertyLogData['contract_id'] = $contractInfo['id'];
        $propertyLogData['room_id'] = $contractInfo['room_id'] ?? 0;
        $propertyLogData['property_id'] = $contractInfo['property_id'];
        $propertyLogData['remark'] = '租赁: ' . $contractInfo['number'] . '退租 ' . $endRemark;
        $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);
    }


    /**
     * 合同签署完成生成第一份账单
     * @param $adminInfo
     * @param $contractInfo
     * @return void
     *
     * @author Amos
     * 2024-05-12 18:16
     */
    private function generateFirstBill($contractInfo, int $userId)
    {
        /** @var BillBasicRepository $billBasicRepository */
        $billBasicRepository = app()->make(BillBasicRepository::class);

        /** @var PropertyLogRepository $propertyLogRepository */
        $propertyLogRepository = app()->make(PropertyLogRepository::class);

        /** @var ContractBillRepository $contractBillRepository */
        $contractBillRepository = app()->make(ContractBillRepository::class);

        /** @var BillCatalogRepository $billCatalogRepository */
        $billCatalogRepository = app()->make(BillCatalogRepository::class);

        ##  生成租金账单
        $rentInfo = $contractBillRepository->getSearch([])
            ->where('contract_id', $contractInfo['id'])
            ->where('if_bill', 2)
            ->where('status', 1)
            ->find();
        if ($rentInfo['amount'] > 0 && $contractInfo['bill_month'] <= 2) {
            $rentStatus = 1; # 待审核账单
            if ($contractInfo['sign_audit'] == 1) {
                $rentStatus = 2; # 自动审核
            }
            $rentBillData = [
                'is_type' => 1,
                'bill_type' => 1,
                'status' => $rentStatus,
                'month_time' => date('Y-m'),
                'create_date' => date("Y-m-d"),
                'contract_id' => $contractInfo['id'],
                'room_id' => $contractInfo['room_id'],
                'items_id' => $contractInfo['items_id'],
                'property_id' => $contractInfo['property_id'],
                'overdue_fine_fee' => (float)$contractInfo['overdue_fine'],
                'number' => $billBasicRepository->generateBillNumber($contractInfo['property_id']),
                'cutoff_date' => date("Y-m-d", strtotime("+{$contractInfo['bill_pay_day']} day")),
            ];
            $rentBillInfo = $billBasicRepository->create($rentBillData);
            # 创建首份租金账单
            if ($rentBillInfo) {
                $monthAmount = 0;
                $rentDay = ((strtotime(date('Y-m-t')) - strtotime($contractInfo['rent_date'])) / (24 * 60 * 60)) + 1;## 本月租金计算天数
                if ($contractInfo['bill_month'] == 1) {
                    ## 本月账单
                    $rentData['end_date'] = date('Y-m-t');
                    $monthDay = date('t');## 本月天数
                    $dayAmount = bcdiv($rentInfo['amount'], $monthDay, 2);## 算出本月一天的租金是多少
                    $monthAmount = bcmul($dayAmount, $rentDay, 2);## 本月租金
                }
                if ($contractInfo['bill_month'] == 2) {
                    ## 次月账单  如是次月账单，必须把本月的也加上去才行
                    $rentData['end_date'] = date('Y-m-t', strtotime('+1 month'));
                    $monthDay = date('t');## 本月天数
                    $dayAmount = bcdiv($rentInfo['amount'], $monthDay, 2);## 算出本月一天的租金是多少
                    $monthAmount = bcadd(bcmul($dayAmount, $rentDay, 2), $rentInfo['amount'], 2);## 本月租金 + 次月租金
                }

                $rentData['is_type'] = 1; # 收入账单
                $rentData['refund_type'] = 1; # 1 正常 2 有退款
                $rentData['amount'] = $monthAmount;
                $rentData['total_amount'] = $monthAmount;
                $rentData['bill_id'] = $rentBillInfo['id'];
                $rentData['status'] = $rentBillInfo['status'];
                $rentData['items_id'] = $rentBillInfo['items_id'];
                $rentData['cate_id'] = $rentInfo['cate_id'];
                $rentData['user_id'] = $contractInfo['user_id'];
                $rentData['month_time'] = $rentBillInfo['month_time'];
                $rentData['contract_id'] = $rentBillInfo['contract_id'];
                $rentData['start_date'] = $contractInfo['rent_date'];## 计租生效日期
                $rentData['property_id'] = $rentInfo['property_id'];
                $billCatalogRepository->create($rentData);

                /** @var ContractBillRepository $contractBillRepository */
                $contractBillRepository = app()->make(ContractBillRepository::class);
                $contractBillList = $contractBillRepository->getSearch([])
                    ->where('if_bill', '3')
                    ->where('status', '1')
                    ->where('contract_id', $contractInfo['id'])
                    ->select();

                $otherDay = ((strtotime(date('Y-m-t')) - strtotime($contractInfo['start_date'])) / (24 * 60 * 60)) + 1;## 其它费用计算天数
                foreach ($contractBillList as $k => $v) {
                    if ($contractInfo['bill_month'] == 1) {
                        ## 本月账单
                        $rentData['end_date'] = date('Y-m-t');
                        $monthDay = date('t');## 本月天数
                        $dayAmount = bcdiv($v['amount'], $monthDay, 2);## 算出本月一天的租金是多少
                        $amount = bcmul($dayAmount, $otherDay, 2);## 本月费用
                    }
                    if ($contractInfo['bill_month'] == 2) {
                        ## 次月账单  如是次月账单，必须把本月的也加上去才行
                        $rentData['end_date'] = date('Y-m-t', strtotime('+1 month'));
                        $monthDay = date('t');## 本月天数
                        $dayAmount = bcdiv($v['amount'], $monthDay, 2);## 算出本月一天的租金是多少
                        $amount = bcadd(bcmul($dayAmount, $otherDay, 2), $v['amount'], 2);## 本月租金 + 次月租金
                    }
                    $otherData['is_type'] = 1;
                    $otherData['amount'] = $amount;
                    $otherData['total_amount'] = $amount;
                    $otherData['cate_id'] = $v['cate_id'];
                    $otherData['bill_id'] = $rentBillInfo['id'];
                    $otherData['property_id'] = $v['property_id'];
                    $otherData['status'] = $rentBillInfo['status'];
                    $otherData['user_id'] = $contractInfo['user_id'];
                    $otherData['items_id'] = $rentBillInfo['items_id'];
                    $otherData['month_time'] = $rentBillInfo['month_time'];
                    $otherData['start_date'] = $contractInfo['start_date'];## 费用计算日期
                    $otherData['contract_id'] = $rentBillInfo['contract_id'];
                    $billCatalogRepository->create($otherData);
                    if ($v['pay_type'] == 4) {
                        # 一次性付
                        $v->status = 2;
                        $v->save();
                    }
                }

                $propertyLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
                $propertyLogData['contract_id'] = $contractInfo['id'];
                $propertyLogData['property_id'] = $contractInfo['property_id'] ?? 0;
                $propertyLogData['remark'] = '租赁编号: ' . $contractInfo['number'] . ' 签署完成 创建首份账单，编号： ' . $rentBillInfo['number'];
                $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);
            }
        }

        ##  生成押金账单
        $depositInfo = $contractBillRepository->getSearch([])
            ->where('contract_id', $contractInfo['id'])
            ->where('if_bill', 1)
            ->where('status', 1)
            ->find();

        if ($depositInfo['amount'] > 0) {
            $depositStatus = 1; # 待审核账单
            if ($contractInfo['sign_audit'] == 1) {
                $depositStatus = 2; # 自动审核
            }
            $depositIBillData = [
                'is_type' => 1,
                'bill_type' => 9,
                'status' => $depositStatus,
                'month_time' => date('Y-m'),
                'create_date' => date("Y-m-d"),
                'contract_id' => $contractInfo['id'],
                'room_id' => $contractInfo['room_id'],
                'items_id' => $contractInfo['items_id'],
                'property_id' => $contractInfo['property_id'],
                'overdue_fine_fee' => (float)$contractInfo['overdue_fine'],
                'number' => $billBasicRepository->generateBillNumber($contractInfo['property_id']),
                'cutoff_date' => date("Y-m-d", strtotime("+{$contractInfo['bill_pay_day']} day")),
            ];
            $depositBillInfo = $billBasicRepository->create($depositIBillData);
            if ($depositBillInfo) {
                ## 添加押金账单明细
                $depositData['is_type'] = 1;
                $depositData['refund_type'] = 1;
                $depositData['bill_id'] = $depositBillInfo['id'];
                $depositData['status'] = $depositBillInfo['status'];
                $depositData['amount'] = $depositInfo['amount'];
                $depositData['items_id'] = $depositBillInfo['items_id'];
                $depositData['cate_id'] = $depositInfo['cate_id'];
                $depositData['user_id'] = $contractInfo['user_id'];
                $depositData['end_date'] = $contractInfo['end_date']; ## 合同结束日期
                $depositData['month_time'] = $depositBillInfo['month_time'];
                $depositData['total_amount'] = $depositInfo['amount'];
                $depositData['contract_id'] = $depositBillInfo['contract_id'];
                $depositData['start_date'] = $contractInfo['start_date'];## 合同开始日期
                $depositData['property_id'] = $depositInfo['property_id'];
                $billCatalogRepository->create($depositData);
            }
            ## 修改状态
            $depositInfo->status = 9;
            $depositInfo->save();

            $propertyLogData['contract_id'] = $contractInfo['id'];
            $propertyLogData['room_id'] = (int)$contractInfo['room_id'] ?? 0;
            $propertyLogData['property_id'] = $contractInfo['property_id'] ?? 0;
            $propertyLogData['remark'] = '租赁编号: ' . $contractInfo['number'] . ' 签署完成 创建押金账单，编号： ' . $depositBillInfo['number'];
            $propertyLogRepository->addData($contractInfo['items_id'], $propertyLogData, $userId);
        }
    }


    public function subscribe(Event $event)
    {
        $event->listen('contract.create', [$this, 'onContractCreate']);## 租赁创建
        $event->listen('contract.auditFinish', [$this, 'onAuditFinishContract']);## 确认审核
        $event->listen('contract.extend', [$this, 'onExtendContract']);## 续租
        $event->listen('contract.refund', [$this, 'onRefundContract']);## 退租
        $event->listen('contract.invalid', [$this, 'onInvalidContract']);## 作废
    }
}